#pragma once
#include <mqcomm/Helper.hpp>
#include <mqcomm/Log.hpp>
#include <mqcomm/Message.pb.h>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>
#include <memory>
#include <cassert>
#include <mutex>
using namespace std;


namespace rbmq {
    // 绑定信息类
    struct Binding {
        typedef shared_ptr<Binding> ptr;
        Binding() {

        }
        Binding(const string& exchange_name, const string& msqueue_name, const string& binding_key) 
            :_exchange_name(exchange_name)
            ,_msqueue_name(msqueue_name)
            ,_binding_key(binding_key)
        {}
        string _exchange_name; // 交换机名称
        string _msqueue_name; // 队列名称
        string _binding_key; // 
    };
    // ---------------------------------------------------------------------------------------------------------------------------------------

    typedef unordered_map<string, Binding::ptr> MsQueueBindingMap; // 队列与其绑定信息的映射表
    typedef unordered_map<string, MsQueueBindingMap> BindingMap;  // 交换机与其绑定的队列的映射表(因为一个交换机可能会有多个队列与它绑定)

    // 绑定信息持久化存储管理类
    class BindingMapper {
    public :
        BindingMapper(const string& dbfile) 
            :_sql_helper(dbfile)
        {
            // 创建数据库
            const string path = FileHelper::parentDiretoty(dbfile);
            if (FileHelper::createDirectory(path)) {
                // 创建数据库
                assert(_sql_helper.open());
            }
            // 创建表
            createTable();
        }
        void createTable() { // 创建数据库表
            const string commd = "create table if not exists binding_table(exchange_name varchar(32), msqueue_name varchar(32), binding_key varchar(128));";
            // 执行语句
            assert(_sql_helper.execute(commd, nullptr, nullptr));
            LOG(Info) << "创建数据库表成功!" << endl;
        }

        void removeTable() { // 删除数据库表
            const string commd = "drop table binding_table;";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }

        bool insert(Binding::ptr binding) { // 新增数据
            char commd[1024];
            sprintf(commd, "insert into binding_table(exchange_name, msqueue_name, binding_key) values('%s', '%s', '%s');",\
             binding->_exchange_name.c_str(), binding->_msqueue_name.c_str(), binding->_binding_key.c_str());
            return _sql_helper.execute(commd, nullptr, nullptr);
        }

        bool remove(const string& exchange_name, const string& msqueue_name) { // 移除数据，可以选择移除交换机或队列
            // 绑定信息的删除条件：exchange_name == msqueue_name
            const string commd = "delete from binding_table where exchange_name='" + exchange_name + "' and msqueue_name='" + msqueue_name + "';";
            // 执行语句
            return _sql_helper.execute(commd, nullptr, nullptr);
        }

        void removeExchangeBinding(const string& exchange_name) { // 移除交换机相关绑定信息
            const string commd = "delete from binding_table where exchange_name='" + exchange_name + "';";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }

        void removeMsQueueBinding(const string& msqueue_name) { // 移除队列相关的绑定信息
            const string commd = "delete from binding_table where msqueue_name='" + msqueue_name + "';";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }
        BindingMap recovery() { // 获取所有的绑定信息
            const string commd = "select exchange_name, msqueue_name, binding_key from binding_table;";
            BindingMap result;
            // 执行语句
            _sql_helper.execute(commd, selectCallback, &result);
            return result;
        }
    private :
        static int selectCallback(void *arg, int numcol, char** row, char** feilds) {
            BindingMap* result = static_cast<BindingMap*>(arg);
            Binding::ptr binding = make_shared<Binding>(row[0], row[1], row[2]);
            MsQueueBindingMap& bm = (*result)[binding->_exchange_name]; // 使用指针，不存在的话就会创建
            bm[binding->_msqueue_name] = binding;
            return 0;
        }

    private :
        SqliteHelper _sql_helper; // 数据库操作句柄
    };
    // ---------------------------------------------------------------------------------------------------------------------------------------


    // 绑定信息数据管理类
    class BindingManager {
    public :
        typedef shared_ptr<BindingManager> ptr;
        BindingManager(const string& dbfile) 
            :_mapper(dbfile)
        {
            // 同样的，每次重启之前都要先恢复数据
            unique_lock<mutex> lock(_mutex);
            _bindings = _mapper.recovery();
        }

        bool bind(const string& exchange_name, const string& msqueue_name, const string& binding_key, bool durable) { // 添加一个绑定信息
            // 先加锁，让后判断绑定信息是否已经存在
            unique_lock<mutex> lock(_mutex);
            // 判断指定的绑定信息是是是否存在
            // 绑定信息是否存在需要满足队列和交换机的绑定信息都存在
            auto eit = _bindings.find(exchange_name);
            if (eit != _bindings.end() && eit->second.find(msqueue_name) != eit->second.end()) {
                return true;
            }
            Binding::ptr binding = make_shared<Binding>(exchange_name, msqueue_name, binding_key);
            MsQueueBindingMap& mbm = _bindings[exchange_name];
            mbm.insert(make_pair(msqueue_name, binding));
            // 绑定信息是否需要持久化，取决于交换机数据是否需要持久化以及队列信息是否需要持久化
            // 所以为了解耦合，所以我们将是否需要持久化，交给外部来判断
            if (durable) {
                bool res = _mapper.insert(binding);
                if (!res) {
                    return false;
                }
            }
            return true;
        }

        void unbind(const string& exchange_name, const string& msqueue_name, bool durable) { // 删除一个绑定信息
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(exchange_name);
            if (eit == _bindings.end()) {
                return;
            }
            auto qit = eit->second.find(msqueue_name);
            if (qit == eit->second.end()) {
                return;
            }
            eit->second.erase(msqueue_name);
            if (durable) {
                _mapper.removeMsQueueBinding(msqueue_name);
            } 
        }

        bool removeExchangeBindings(const string& exchange_name, bool durable) { // 移除交换机绑定信息
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(exchange_name);
            if (eit == _bindings.end()) {
                return true;
            }
            _bindings.erase(exchange_name);
            if (durable) {
                _mapper.removeExchangeBinding(exchange_name);
            }
            return true;
        }

        void removeMsQueueBindings(const string& msqueue_name, bool durable) { // 移除队列绑定信息  
            unique_lock<mutex> lock(_mutex);
            // 可能有多个交换机与一个队列相关联
            // 所以我们需要遍历所有的交换机，从中删除制定队列的相关绑定信息
            for (auto it = _bindings.begin(); it != _bindings.end(); it++) {
                if (it->second.find(msqueue_name) != it->second.end()) {
                    it->second.erase(msqueue_name);
                    if (durable) {
                        _mapper.removeMsQueueBinding(msqueue_name);
                    }
                }
            }
            
        }

        MsQueueBindingMap getExchangeBindings(const string& exchange_name) { // 获取指定交换机绑定信息
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(exchange_name);
            if (eit == _bindings.end()) {
                return MsQueueBindingMap();
            }
            return _bindings[exchange_name];
        }
        
        Binding::ptr getBinding(const string& exchange_name, const string& msqueue_name) { // 获取指定的绑定信息
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(exchange_name);
            if (eit == _bindings.end()) {
                return Binding::ptr();
            }
            auto qit = eit->second.find(msqueue_name);
            if (qit == eit->second.end()) {
                return Binding::ptr();
            }
            return qit->second;
        }

        bool exists(const string& exchange_name, const string& msqueue_name) {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(exchange_name);
            if (eit == _bindings.end()) {
                return false;
            }
            auto qit = eit->second.find(msqueue_name);
            if (qit == eit->second.end()) {
                return false;
            }
            return true;
        }
        size_t size() { // 获取一共有多少个绑定信息
            unique_lock<mutex> lock(_mutex);
            // 遍历每一个交换机，看每个交换机里面有多少的绑定信息
            size_t ret = 0;
            for (auto it = _bindings.begin(); it != _bindings.end(); it++) {
                ret += it->second.size();
            }
            return ret;
        }

        void clear() {
            unique_lock<mutex> lock(_mutex);
            _bindings.clear();
            _mapper.removeTable();
        }

    private :
        BindingMapper _mapper; // 磁盘中数据的管理
        BindingMap _bindings; // 内存中数据的管理
        mutex _mutex; // 互斥锁
    };
};



